/**
 * @File:ring_buffer.c
 * @Version:V1.2
 * @Author:rudius
 * @Brief:
 * @Logs:
 * 	Date		Author		Notes
 * 	2025-06-17	rudius		first version
 * 	2025-06-27	rudius		fixed buffer handling and thread safety
 * 	2025-06-28	rudius		fixed full state and pointer wrap handling
 */

// <<< Use Configuration Wizard in Context Menu >>>

/* Private includes --------------------------------------------------------- */
#include "ring_buffer.h"
#include <rtthread.h>
#include <string.h>
#ifdef __cplusplus
extern "C"
{
#endif

/* Private config ----------------------------------------------------------- */
/* Private defines ---------------------------------------------------------- */
#ifndef ALIGN_SIZE
#define ALIGN_SIZE(size, align) (((size) + (align) - 1) & ~((align) - 1))
#endif
    /* Private typedef ---------------------------------------------------------- */
    /* Private variables -------------------------------------------------------- */
    /* Private function prototypes ---------------------------------------------- */

    /*----------------------------------------------------------------------------*/
    /* Private functions -------------------------------------------------------- */

    /* 线程安全的内部函数 */
    static rt_size_t ring_buf_data_size_locked(ring_buf_t *rb)
    {
        if (rb->is_full)
        {
            return rb->buffer_size;
        }

        if (rb->write_index >= rb->read_index)
        {
            return rb->write_index - rb->read_index;
        }

        return rb->buffer_size - rb->read_index + rb->write_index;
    }

    static rt_size_t ring_buf_free_space_locked(ring_buf_t *rb)
    {
        if (rb->is_full)
        {
            return 0;
        }

        rt_size_t data_size = ring_buf_data_size_locked(rb);
        return rb->buffer_size - data_size;
    }

    /* Public functions --------------------------------------------------------- */
    rt_err_t ring_buf_init(ring_buf_t *rb, rt_size_t size)
    {
        RT_ASSERT(rb != RT_NULL);

        /* 计算对齐后的缓冲区大小 */
        rt_size_t aligned_size = ALIGN_SIZE(size, RINGBUF_ALIGNMENT);

        /* 分配对齐的缓冲区内存 */
        rb->buffer_ptr = rt_malloc(aligned_size);
        if (rb->buffer_ptr == RT_NULL)
        {
            return -RT_ENOMEM;
        }

        /* 初始化缓冲区状态 */
        rb->buffer_size = aligned_size;
        rb->read_index = 0;
        rb->write_index = 0;
        rb->is_full = RT_FALSE;

#ifdef USER_RING_BUFFER_THREAD_SAFE
        /* 初始化互斥锁 */
        rt_err_t result = rt_mutex_init(&rb->lock, "ringbuf", RT_IPC_FLAG_FIFO);
        if (result != RT_EOK)
        {
            rt_free(rb->buffer_ptr);
            return result;
        }
#endif

        return RT_EOK;
    }

    void ring_buf_detach(ring_buf_t *rb)
    {
        RT_ASSERT(rb != RT_NULL);

        if (rb->buffer_ptr)
        {
            rt_free(rb->buffer_ptr);
            rb->buffer_ptr = RT_NULL;
        }

#ifdef USER_RING_BUFFER_THREAD_SAFE
        rt_mutex_detach(&rb->lock);
#endif
    }

    ring_buf_t *ring_buf_create(rt_size_t size)
    {
        ring_buf_t *rb = (ring_buf_t *)rt_malloc(sizeof(ring_buf_t));
        if (rb == RT_NULL)
        {
			rt_kprintf("ring buffer have no space to allocate!\n");
            return RT_NULL;
        }

        /* 初始化实例 */
        if (ring_buf_init(rb, size) != RT_EOK)
        {
            rt_free(rb);
            return RT_NULL;
        }

        return rb;
    }

    void ring_buf_destroy(ring_buf_t *rb)
    {
        if (rb)
        {
            ring_buf_detach(rb);
            rt_free(rb);
        }
    }

/* 线程安全宏封装 */
#ifdef USER_RING_BUFFER_THREAD_SAFE
#define RING_BUF_LOCK(rb) rt_mutex_take(&(rb)->lock, RT_WAITING_FOREVER)
#define RING_BUF_UNLOCK(rb) rt_mutex_release(&(rb)->lock)
#else
#define RING_BUF_LOCK(rb) (void)0
#define RING_BUF_UNLOCK(rb) (void)0
#endif

    rt_size_t ring_buf_put(ring_buf_t *rb, const rt_uint8_t *data, rt_size_t length)
    {
        RT_ASSERT(rb != RT_NULL);
        RT_ASSERT(data != RT_NULL);

        if (length == 0)
        {
            return 0;
        }

        RING_BUF_LOCK(rb);

        /* 计算可写入空间 */
        rt_size_t free_space = ring_buf_free_space_locked(rb);

        /* 如果空间不足则覆盖旧数据 */
        if (length > free_space)
        {
            /* 计算需要丢弃的数据量 */
            rt_size_t discard_size = length - free_space;

            /* 更新读指针以丢弃旧数据 */
            rb->read_index = (rb->read_index + discard_size) % rb->buffer_size;
            rb->is_full = RT_FALSE;
        }

        /* 计算连续写入空间 */
        rt_size_t remain = rb->buffer_size - rb->write_index;

        if (length <= remain)
        {
            /* 单次写入即可完成 */
            memcpy(rb->buffer_ptr + rb->write_index, data, length);
            rb->write_index += length;
        }
        else
        {
            /* 需要分两次写入 */
            rt_size_t first_part = remain;
            memcpy(rb->buffer_ptr + rb->write_index, data, first_part);
            rt_size_t second_part = length - first_part;
            memcpy(rb->buffer_ptr, data + first_part, second_part);
            rb->write_index = second_part;
        }

        /* 处理写指针回绕 */
        if (rb->write_index >= rb->buffer_size)
        {
            rb->write_index = 0;
        }

        /* 更新满状态标志: 如果写指针等于读指针且写入长度不为0 */
        if (rb->write_index == rb->read_index && length > 0)
        {
            rb->is_full = RT_TRUE;
        }
        else
        {
            rb->is_full = RT_FALSE;
        }

        RING_BUF_UNLOCK(rb);

        return length;
    }

    rt_size_t ring_buf_get(ring_buf_t *rb, rt_uint8_t *data, rt_size_t length)
    {
        RT_ASSERT(rb != RT_NULL);
        RT_ASSERT(data != RT_NULL);

        if (length == 0)
        {
            return 0;
        }

        RING_BUF_LOCK(rb);

        if (ring_buf_data_size_locked(rb) == 0)
        {
            RING_BUF_UNLOCK(rb);
            return 0;
        }

        /* 计算可读取数据量 */
        rt_size_t data_size = ring_buf_data_size_locked(rb);
        rt_size_t read_size = (length < data_size) ? length : data_size;

        /* 计算连续读取空间 */
        rt_size_t cont_read_space;
        if (rb->is_full)
        {
            // 满状态时连续空间 = 缓冲区大小 - 读指针位置
            cont_read_space = rb->buffer_size - rb->read_index;
        }
        else
        {
            if (rb->write_index >= rb->read_index)
            {
                cont_read_space = rb->write_index - rb->read_index;
            }
            else
            {
                cont_read_space = rb->buffer_size - rb->read_index;
            }
        }

        if (read_size <= cont_read_space)
        {
            /* 单次读取即可完成 */
            memcpy(data, rb->buffer_ptr + rb->read_index, read_size);
            rb->read_index += read_size;
        }
        else
        {
            /* 需要分两次读取 */
            rt_size_t first_part = cont_read_space;
            memcpy(data, rb->buffer_ptr + rb->read_index, first_part);
            rt_size_t second_part = read_size - first_part;
            memcpy(data + first_part, rb->buffer_ptr, second_part);
            rb->read_index = second_part;
        }

        /* 处理读指针回绕 */
        if (rb->read_index >= rb->buffer_size)
        {
            rb->read_index = 0;
        }

        /* 清除满状态标志 */
        rb->is_full = RT_FALSE;

        RING_BUF_UNLOCK(rb);

        return read_size;
    }

    rt_size_t ring_buf_data_size(ring_buf_t *rb)
    {
        RT_ASSERT(rb != RT_NULL);

        RING_BUF_LOCK(rb);
        rt_size_t size = ring_buf_data_size_locked(rb);
        RING_BUF_UNLOCK(rb);
        return size;
    }

    rt_bool_t ring_buf_is_empty(ring_buf_t *rb)
    {
        RT_ASSERT(rb != RT_NULL);

        RING_BUF_LOCK(rb);
        rt_bool_t empty = (!rb->is_full) && (rb->read_index == rb->write_index);
        RING_BUF_UNLOCK(rb);
        return empty;
    }

    rt_bool_t ring_buf_is_full(ring_buf_t *rb)
    {
        RT_ASSERT(rb != RT_NULL);

        RING_BUF_LOCK(rb);
        rt_bool_t full = rb->is_full;
        RING_BUF_UNLOCK(rb);
        return full;
    }

    void ring_buf_reset(ring_buf_t *rb)
    {
        RT_ASSERT(rb != RT_NULL);

        RING_BUF_LOCK(rb);

        rb->read_index = 0;
        rb->write_index = 0;
        rb->is_full = RT_FALSE;

        RING_BUF_UNLOCK(rb);
    }

#ifdef __cplusplus
}
#endif
// <<< end of configuration section >>>
/* ----------------------------- end of ring_buffer.c ---------------------------- */